'use strict';
const BaseService = require('./base');
const ResponseUtil = require('../utils/ResponseUtil');
const VRCE = require('../utils/ViewResultCodeEnum');
const StringUtil = require('../utils/StringUtil');
const Constant = require('../config/Constant');

class SysRoleService extends BaseService {


    async selectRolePermissionByUserId(userId) {
        let sql = `
                    select r.role_id, r.role_name, r.role_key, r.role_sort,
                        r.status, r.del_flag, r.create_by, r.create_time, r.update_by, r.update_time, r.remark
                        from sys_role r
                                     left join sys_user_role ur on ur.role_id = r.role_id
                                     left join sys_user u on u.user_id = ur.user_id
                    WHERE r.del_flag = 0 and u.user_id = ?
                  `;
        let result = await this.executeSql(sql, [userId]);
        let respSet = new Set();
        for (let i = 0; i < result.length; i++) {
            let item = result[i];
            if (item.roleKey)
                respSet.add(item.roleKey);
        }
        let respList = Array.from(respSet);
        return respList;
    }


    async selectRoleList({pageNum, pageSize, roleName, status, delFlag}) {
        let loginUserInfo = this.ctx.getLoginInfo();
        let operatorType = loginUserInfo.operatorType;
        let operatorId = loginUserInfo.operatorId;
        let createBy = loginUserInfo.createBy;
        let tenantId = loginUserInfo.tenantId;

        let sql_list = `    select r.role_id, r.role_name, r.role_key, r.role_sort,
                         r.status, r.del_flag, r.create_by, r.create_time, r.update_by, r.update_time, r.remark, r.create_by_id, r.update_by_id `
        let sql_count = `select count(*) as count `;
        let sql = `
                       from sys_role r where 1=1
                  `;

        let wheres = [
            {column: 'tenant_id', value: tenantId, options: {tname: 'r'}},
            {column: 'role_name', value: roleName, options: {tname: 'r', condition: 'like'}},
            {column: 'status', value: status, options: {tname: 'r'}},
            {column: 'del_flag', value: delFlag, options: {tname: 'r'}}
        ];

        let formatSqlResult = this.formatSqlWhere(sql, wheres);

        sql = formatSqlResult[0];

        sql_count += sql;

        sql += ` order by r.role_sort asc, r.create_time desc `;

        sql_list += sql;

        sql_list = this.addMysqlPageSize(sql_list, pageNum, pageSize);

        let list = await this.executeSql(sql_list, formatSqlResult[1]);

        for (let i = 0; i < list.length; i++) {
            list[i].admin = this.isAdmin(list[i].roleId);
        }

        let countRet = await this.executeSqlFirst(sql_count, formatSqlResult[1]);

        return {list: list, total: countRet.count};
    }

    async checkRoleNameUnique(role) {
        let roleId = role.roleId || 0;
        let sql = 'select * from sys_role where role_name=? limit 1';
        let info = await this.executeSqlFirst(sql, [role.roleName]);
        if (info != null && info.roleId != roleId) {
            return Constant.NOT_UNIQUE;
        }
        return Constant.UNIQUE;
    }

    async checkRoleKeyUnique(role) {
        let roleId = role.roleId || 0;
        let sql = 'select * from sys_role where role_key=? limit 1';
        let info = await this.executeSqlFirst(sql, [role.roleKey]);
        if (info != null && info.roleId != roleId) {
            return Constant.NOT_UNIQUE;
        }
        return Constant.UNIQUE;
    }

    async insertRole(role) {
        if (Constant.NOT_UNIQUE == (await this.checkRoleNameUnique(role))) {
            return ResponseUtil.resError(VRCE.ADMIN_ROLE_NAME_EXIST[1], VRCE.ADMIN_ROLE_NAME_EXIST[0]);
        }
        if (Constant.NOT_UNIQUE == (await this.checkRoleKeyUnique(role))) {
            return ResponseUtil.resError(VRCE.ADMIN_ROLE_KEY_EXIST[1], VRCE.ADMIN_ROLE_KEY_EXIST[0]);
        }
        let conn = await this.app.mysql.beginTransaction();

        try {

            let loginUserInfo = this.ctx.getLoginInfo();
            let operatorType = loginUserInfo.operatorType;
            let operatorId = loginUserInfo.operatorId;
            let createBy = loginUserInfo.createBy;
            let tenantId = loginUserInfo.tenantId;

            let menuIds = role.menuIds;


            let roleParams = {
                tenant_id:tenantId,
                role_name: role.roleName,
                role_key: StringUtil.getUUIDV2(),
                role_sort: role.roleSort,
                status: role.status || 0,
                del_flag: 0,
                create_by: createBy,
                create_by_id: operatorId,
                remark: role.remark,
                create_time: new Date(),
                update_time: new Date()
            };

            let insertRoleResult = await conn.insert('sys_role', roleParams);

            if (!insertRoleResult.affectedRows) {
                throw Error('insert role error');
            }

            if (menuIds && Array.isArray(menuIds) && menuIds.length > 0) {
                for (let i = 0; i < menuIds.length; i++) {
                    let params = {
                        role_id: insertRoleResult.insertId,
                        menu_id: menuIds[i]
                    };
                    let insertRoleMenuResult = await conn.insert('sys_role_menu', params);
                    if (!insertRoleMenuResult.affectedRows) {
                        throw Error('insert role menu error');
                        break;
                    }
                }
            }

            await conn.commit();
            return insertRoleResult.insertId;

        } catch (e) {
            this.ctx.app.logger.error('insertRole error', e.message);
            await conn.rollback();
            throw Error(e.message);
        }
    }

    isAdmin(roleId) {
        return roleId != null && 1 == roleId;
    }

    async updateRole(role) {

        let isAdmin = this.isAdmin(role.roleId);

        if (isAdmin) {
            return ResponseUtil.resError(VRCE.ADMIN_ROLE_NOT_OPER[1], VRCE.ADMIN_ROLE_NOT_OPER[0]);
        }

        if (Constant.NOT_UNIQUE == (await this.checkRoleNameUnique(role))) {
            return ResponseUtil.resError(VRCE.ADMIN_ROLE_NAME_EXIST[1], VRCE.ADMIN_ROLE_NAME_EXIST[0]);
        }
        if (Constant.NOT_UNIQUE == (await this.checkRoleKeyUnique(role))) {
            return ResponseUtil.resError(VRCE.ADMIN_ROLE_KEY_EXIST[1], VRCE.ADMIN_ROLE_KEY_EXIST[0]);
        }

        let conn = await this.app.mysql.beginTransaction();

        try {

            let loginUserInfo = this.ctx.getLoginInfo();
            let operatorType = loginUserInfo.operatorType;
            let operatorId = loginUserInfo.operatorId;
            let createBy = loginUserInfo.createBy;
            let tenantId = loginUserInfo.tenantId;

            let roleObj = await this.selectRoleById(role.roleId);
            if(!roleObj){
                throw Error('未找到角色');
            }
            if(roleObj.tenantId != tenantId){
                throw Error('无权限操作');
            }

            let menuIds = role.menuIds;


            let roleParams = {
                role_name: role.roleName,
                role_sort: role.roleSort,
                status: role.status || 0,
                update_by: createBy,
                update_by_id: operatorId,
                remark: role.remark,
                update_time: new Date()
            };

            const options = {
                where: {
                    role_id: role.roleId
                }
            };

            let updateRoleResult = await conn.update('sys_role', roleParams, options);

            if (!updateRoleResult.affectedRows) {
                throw Error('update role error');
            }

           /* const delSize = await this.ctx.service.sysRoleMenu.deleteRoleMenuByRoleId(role.roleId, conn);

            if (delSize <= 0) {
                //throw Error('delete role menu error');
            }

            if (menuIds && Array.isArray(menuIds) && menuIds.length > 0) {
                for (let i = 0; i < menuIds.length; i++) {
                    let params = {
                        role_id: role.roleId,
                        menu_id: menuIds[i]
                    };
                    let insertRoleMenuResult = await conn.insert('sys_role_menu', params);
                    if (!insertRoleMenuResult.affectedRows) {
                        throw Error('insert role menu error');
                        break;
                    }
                }
            }*/

            await conn.commit();
            return role.roleId;

        } catch (e) {
            this.ctx.app.logger.error('updateRole error', e.message);
            await conn.rollback();
            throw Error(e.message);
        }

    }


    async updateRolePerms(role){
        let isAdmin = this.isAdmin(role.roleId);

        if (isAdmin) {
            return ResponseUtil.resError(VRCE.ADMIN_ROLE_NOT_OPER[1], VRCE.ADMIN_ROLE_NOT_OPER[0]);
        }

        let conn = await this.app.mysql.beginTransaction();

        try {

            let loginUserInfo = this.ctx.getLoginInfo();
            let operatorType = loginUserInfo.operatorType;
            let operatorId = loginUserInfo.operatorId;
            let createBy = loginUserInfo.createBy;
            let tenantId = loginUserInfo.tenantId;

            let roleObj = await this.selectRoleById(role.roleId);
            if(!roleObj){
                throw Error('未找到角色');
            }
            if(roleObj.tenantId != tenantId){
                throw Error('无权限操作');
            }

            let menuIds = role.menuIds;

            const delSize = await this.ctx.service.sysRoleMenu.deleteRoleMenuByRoleId(role.roleId, conn);

            if (delSize <= 0) {
                //throw Error('delete role menu error');
            }

            if (menuIds && Array.isArray(menuIds) && menuIds.length > 0) {
                for (let i = 0; i < menuIds.length; i++) {
                    let params = {
                        role_id: role.roleId,
                        menu_id: menuIds[i]
                    };
                    let insertRoleMenuResult = await conn.insert('sys_role_menu', params);
                    if (!insertRoleMenuResult.affectedRows) {
                        throw Error('insert role menu error');
                        break;
                    }
                }
            }

            await conn.commit();
            return role.roleId;

        } catch (e) {
            this.ctx.app.logger.error('updateRolePerms error', e.message);
            await conn.rollback();
            throw Error(e.message);
        }

    }


    async selectRoleById(roleId) {
        let sql = `  select r.tenant_id,r.role_id, r.role_name, r.role_key, r.role_sort,
            r.status, r.del_flag, r.create_by, r.create_time, r.update_by, r.update_time, r.remark, r.create_by_id, r.update_by_id
        from sys_role r where r.role_id = ?`;
        let result = await this.executeSqlFirst(sql, [roleId]);
        return result;
    }


    async getRoleListAll({roleName, roleId, status, roleKey, delFlag}) {
        let sql = `select r.role_id, r.role_name, r.role_key, r.role_sort,
            r.status, r.del_flag, r.create_by, r.create_time, r.update_by, r.update_time, r.remark, r.create_by_id, r.update_by_id
        from sys_role r where 1=1 `;

        let loginUserInfo = this.ctx.getLoginInfo();
        let operatorType = loginUserInfo.operatorType;
        let operatorId = loginUserInfo.operatorId;
        let createBy = loginUserInfo.createBy;
        let tenantId = loginUserInfo.tenantId;

        let wheres = [
            {column: 'tenant_id', value: tenantId, options: {tname: 'r'}},
            {column: 'role_id', value: roleId, options: {tname: 'r'}},
            {column: 'role_name', value: roleName, options: {tname: 'r', condition: 'like'}},
            {column: 'role_key', value: roleKey, options: {tname: 'r', condition: 'like'}},
            {column: 'status', value: status, options: {tname: 'r'}},
            {column: 'del_flag', value: delFlag, options: {tname: 'r'}}
        ];

        let formatSqlResult = this.formatSqlWhere(sql, wheres);

        sql = formatSqlResult[0];

        let result = await this.executeSql(sql, formatSqlResult[1]);
        return result;
    }

    async countUserRoleByRoleId(roleId) {
        let sql = `select count(1) as count from sys_user_role where role_id=?  `;
        let result = await this.executeSqlFirst(sql, [roleId]);
        return result ? result.count || 0 : 0;
    }

    async deleteRoleById(roleId) {
        let isAdmin = this.isAdmin(roleId);

        if (isAdmin) {
            return ResponseUtil.resError(VRCE.ADMIN_ROLE_NOT_OPER[1], VRCE.ADMIN_ROLE_NOT_OPER[0]);
        }

        const count = this.countUserRoleByRoleId(roleId);

        if (count > 0) {
            return ResponseUtil.resError(VRCE.ADMIN_ROLE_FP_EXIST[1], VRCE.ADMIN_ROLE_FP_EXIST[0]);
        }

        let loginUserInfo = this.ctx.getLoginInfo();
        let operatorType = loginUserInfo.operatorType;
        let operatorId = loginUserInfo.operatorId;
        let createBy = loginUserInfo.createBy;
        let tenantId = loginUserInfo.tenantId;

        let roleObj = await this.selectRoleById(roleId);
        if(!roleObj){
            return ResponseUtil.resError('未找到角色');
        }
        if(roleObj.tenantId != tenantId){
            return ResponseUtil.resError('无权限操作');
        }


        let conn = await this.app.mysql.beginTransaction();

        try {

            const delSize = await this.ctx.service.sysRoleMenu.deleteRoleMenuByRoleId(roleId, conn);

            if (delSize <= 0) {
               // throw Error('delete role menu error');
            }

            let sql = `delete from sys_role where role_id =?`;
            let delSize2 = await this.executeSqlSucc(sql, [roleId], conn);

            if (delSize2 <= 0) {
                throw Error('delete role error');
            }

            await conn.commit();
            return roleId;

        } catch (e) {
            this.ctx.app.logger.error('deleteRoleById error', e.message);
            await conn.rollback();
            throw Error(e.message);
        }
    }


}

module.exports = SysRoleService;
